#include <iostream>
#include <boost/lexical_cast.hpp>
#include "pcap++/PcapOffline.h"
#include "pcap++/PcapLive.h"
#include "pcap++/config.h"
#include <pcap++/Packet.h>
#include <pcap++/DataLink.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <map>
#include <list>
#include <queue>

#define FRONT_ENGINE 4200

#include "udp_server.h"
#include "udp_sender.h"
#include "agent/agent.h"
#include "frame.h"
#include "FilterContainer.h"
#include "front/AcceptedFlow.h"

FilterContainer g_filterContainer;
AcceptedFlow g_acceptedFlow;

void handle(pcappp::Pcap& pcap, pcappp::Packet const& packet)
{
	Frame frame(packet);

	if( ! frame.isOK())
		return;
	if(frame.IPprotocol() == TCP_PROTOCOL)
	{
		FlowID flow_id = frame.getFlowID();

		if(UDPSenderPointer udpSender = g_filterContainer.validate(frame))
		{
			g_acceptedFlow.add(flow_id, udpSender);

			com::Block block;
			block.mutable_flowpacket()->set_payload(packet.get_data(), packet.get_capture_length());
			block.mutable_flowpacket()->set_flowid(flow_id);
			udpSender->sendString(block);
		}
		else if(UDPSenderPointer udpSender = g_acceptedFlow.find(flow_id))
		{
			com::Block block;
			block.mutable_flowpacket()->set_payload(packet.get_data(), packet.get_capture_length());
			block.mutable_flowpacket()->set_flowid(flow_id);
			udpSender->sendString(block);
		}
	}
}
/*
void *front_engine_thread(void*)
{
	udp_server server(FRONT_ENGINE);

	while(1)
	{
		com::Block block = server.getBlock();
		if(block.has_subscription())
		{
			BaseFilterPointer newFilter = createFilter(block.subscription());

			uint32_t agentPort = block.mutable_subscription()->agentport();
			std::string agentname = block.mutable_subscription()->agentname();

			g_filterContainer.addFilter(newFilter, agentname, agentPort, inet_ntoa(server.getClientIP()));

			std::cout << "new subscription from " << agentname << std::endl;
		}
		if(block.has_subscription_heartbeat())
		{
			std::cout << "subscription_heartbeat=" << block.subscription_heartbeat().agentname() << std::endl;
			g_filterContainer.updateSubscriptionContainer(block.subscription_heartbeat().agentname());
		}
	}

	return 0;
}
*/
int main(int argc, char *argv[])
{
//	pthread_t t1;
//	pthread_create(&t1, NULL, &front_engine_thread, NULL);

	pcappp::PcapLive eth3("eth3");
	eth3.loop(handle);

	return 0;
}
